package whf.framework.util;

import java.beans.PropertyDescriptor;
import java.util.List;

import whf.framework.entity.Entity;
import whf.framework.exception.PropertyException;
import whf.framework.log.entity.AuditHistoryDetail;
import whf.framework.meta.MetaManager;
import whf.framework.meta.entity.IMeta;
import whf.framework.meta.entity.IProperty;
import whf.framework.meta.entity.ObjectProperty;
import whf.framework.web.struts.AbstractStrutsForm;

/**
 * 获取对象改变属性
 * @author wanghaifeng
 *
 */
@SuppressWarnings("unchecked")
public class PropertyChangeUtils {
	
	/**
	 * @param oldObject	原对象
	 * @param newObject 修改后的新对象
	 * @return Map<<propertyName, propertyTitle>,<oldValue, newValue>> 返回属性改变记录
	 */
	public static List<AuditHistoryDetail> getPropertyChangeLog(IMeta meta, Object oldObject, Object newObject) throws Exception{
		assert oldObject != null && newObject != null: "oldObject and newObject can't be null!";
		assert meta instanceof whf.framework.meta.entity.Object: "Meta must be a whf.framework.meta.entity.Object instance";
		List<AuditHistoryDetail> result = Utils.newArrayList();
		PropertyDescriptor[] descriptors = null;
		if(newObject != null)
			descriptors  = BeanUtils.getPropertyDescriptors(newObject.getClass());
		if(oldObject != null) 
			descriptors = BeanUtils.getPropertyDescriptors(oldObject.getClass());
		for(PropertyDescriptor descriptor: descriptors){
			String propertyName = descriptor.getName();
			if(newObject instanceof Entity && BeanUtils.hasProperty(AbstractStrutsForm.class, propertyName)){
				continue;
			}
			// 过滤掉修改时间修改日期等属性变更信息，否则会导致无穷尽的属性变更
			if(StringUtils.equalsIgnoreCase(propertyName, "updateDate") || 
					StringUtils.equalsIgnoreCase(propertyName, "updateBy") || 
					StringUtils.equalsIgnoreCase(propertyName, "lastIndexTime")) {
				continue;
			}
			// end
			String propertyTitle = propertyName;
			if(meta != null && meta.findProperty(propertyName) != null){
				IProperty iProperty = meta.findProperty(propertyName);
				if(iProperty instanceof ObjectProperty) {
					ObjectProperty op = (ObjectProperty)iProperty;
					if(!op.isAuditable()) continue;
				}
				propertyTitle = iProperty.getDisplayTitle();
			}
			try{
				Class propType = descriptor.getPropertyType();
				Object newValue = BeanUtils.getProperty(newObject, propertyName);
				Object oldValue = BeanUtils.getProperty(oldObject, propertyName);
				if(newValue == null && oldValue == null) continue;
				if(TypeUtils.isPrimitiveType(propType)){
					String newString = newValue == null? "": newValue.toString();
					String oldString = oldValue == null? "": oldValue.toString();
					if(StringUtils.equals(newString, oldString)) continue;
					AuditHistoryDetail detail = new AuditHistoryDetail(propertyTitle, propertyName, propType.getName(), oldString, newString);
					result.add(detail);
				} else if(TypeUtils.isImplementsFrom(propType, Entity.class)){
					Entity newBO = (Entity)newValue;
					Entity oldBO = (Entity)oldValue;
					String newString = newBO == null? "": newBO.getName();
					String oldString = oldBO == null? "": oldBO.getName();
					if(StringUtils.equals(newString, oldString)) continue;
					AuditHistoryDetail detail = new AuditHistoryDetail(propertyTitle, propertyName, propType.getName(), oldString, newString);
					result.add(detail);
				}
			}catch(PropertyException e){
				continue;
			}
		}
		return result;
	}
	
	public static List<AuditHistoryDetail> getPropertyChangeLog(Object oldObject, Object newObject) throws Exception{
		if(oldObject == null || newObject == null) 
			throw new IllegalArgumentException("oldObject and newObject can't be null!");
		String boClassName = newObject.getClass().getName();
		whf.framework.meta.entity.Object meta = MetaManager.getDefaultInstance().findByEntityClass(boClassName);
		return getPropertyChangeLog(meta, oldObject, newObject);
	}
}
